package com.common.base.http.main

import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.common.base.R
import com.common.base.http.exceptions.CloudException
import com.common.base.tools.utils.ApplicationUtils
import com.common.base.tools.obj.LoadingObj
import com.common.base.manager.StackManager
import com.common.base.tools.utils.logger
import io.reactivex.subscribers.ResourceSubscriber
import retrofit2.HttpException
import java.lang.reflect.Field
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.net.UnknownHostException

/**
 * Created by zsf on 2022/8/17 14:58
 * *******************
 *    处理器
 * *******************
 */
/**
 * @param mContext 当前Activity的上线文  可选  不传默认使用最上层的activity栈
 * @param isShowDialog 是否显示加载动画  可选
 * @param isShowLogin Token失效了，是否跳转到登录页  可选
 */
abstract class ApiSubscriber<T> @JvmOverloads constructor(
    private val isShowLoad: Boolean = false,
    private val mContext: AppCompatActivity = StackManager.getActivityManager().currentActivity(),
    private val isShowLogin: Boolean = false,
) : ResourceSubscriber<T>() {

    override fun onStart() {
        super.onStart()
        try {
            if (isShowLoad)
                LoadingObj.showLoad(mContext)
        } catch (e: Exception) {
            logger.error(e.message,e)
            e.printStackTrace()
        }
    }

    override fun onNext(it: T) {
        onResponseHandler(it)//直接返回
        try {
            val obj = it!!::class.java
            //获取父类的属性
            var fieldCode = getDeclaredField(it, ApiConfig.CODE_NAME)
            if (fieldCode == null) {
                //获取子类的属性
                fieldCode = obj.getDeclaredField(ApiConfig.CODE_NAME)
            }
            fieldCode?.isAccessible = true
            when (fieldCode?.get(it)) {
                CODE_SUCCESS ->//成功
                    onSuccessHandler(it)
                CODE_TOKEN_INVALID -> {//token失效
                    onFailHandler(it)
//                    ARouter.getInstance().build(RouterConstants.Path.BASE_CONTAINER)
//                        .withString(RouterConstants.KV.PAGE_PATH, RouterConstants.Path.BASE_NO_NETWORK)
//                        .navigation()
                }
                else -> {// 失败
                    onFailHandler(it)
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
            logger.error(e.message,e)
        }
    }

    override fun onError(t: Throwable) {
        try {
            LoadingObj.hintLoad()
            val exception = accept(t)
            onErrorHandle(exception)
            onCompleteHandler()
        } catch (e: Exception) {
            e.printStackTrace()
            logger.error(e.message,e)
        }
    }

    override fun onComplete() {
        try {
            LoadingObj.hintLoad()
            onCompleteHandler()
        } catch (e: Exception) {
            e.printStackTrace()
            logger.error(e.message,e)
        }
    }

    private fun accept(t: Throwable): CloudException? {
        return try {
            when (t) {
                is CloudException -> {
                    t
                }
                is SocketTimeoutException -> {
                    CloudException(CODE_NO_NETWORK, SOCKET_TIME_OUT_EXCEPTION)
                }
                is ConnectException -> {
                    CloudException(CODE_NO_NETWORK, CONNECT_EXCEPTION)
                }
                is UnknownHostException -> {
                    CloudException(CODE_NO_NETWORK, UNKNOWN_HOST_EXCEPTION)
                }
                is HttpException -> {
                    CloudException(CODE_NO_NETWORK, SOCKET_TIME_OUT_EXCEPTION)
//                    CloudException(t.code(), t.message)
                }
                else -> {
                    CloudException(CODE_UNKNOWN, t.message)
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
            CloudException(CODE_UNKNOWN, e.message)
        }
    }

    /**
     * 非必实现，成功的返回（code == 200），修改code 在ApiConfig文件中
     * @param t 返回的对象
     */
    protected open fun onSuccessHandler(t: T) {}

    /**
     * 非必实现，失败 code ！= 200
     * @param t 返回的对象
     */
    protected open fun onFailHandler(t: T) {}

    /**
     * 非必实现，整个请求完成的回调，方便做刷新动画的结束标志等
     */
    protected open fun onCompleteHandler() {}

    /**
     *  非必实现，不判断成功还是失败，直觉返回，跟onSuccess、onFail互斥，二选一
     */
    protected open fun onResponseHandler(t: T) {}

    /**
     * 错误，非200 的返回
     */
    protected open fun onErrorHandle(exception: CloudException?) {
        try {
            exception.let {
                Toast.makeText(ApplicationUtils.context(),exception?.message, Toast.LENGTH_LONG).show()
            }
        } catch (e: Exception) {
            e.printStackTrace()
            logger.error(e.message,e)
        }
    }


    companion object {
        private val SOCKET_TIME_OUT_EXCEPTION =
            ApplicationUtils.context().resources.getString(R.string.network_no_message)
        private val CONNECT_EXCEPTION =
            ApplicationUtils.context().resources.getString(R.string.network_no_message)
        private val UNKNOWN_HOST_EXCEPTION =
            ApplicationUtils.context().resources.getString(R.string.network_no_message)
    }

    /**
     * 循环向上转型, 获取对象的 DeclaredField
     * @param object : 子类对象
     * @param fieldName : 父类中的属性名
     * @return 父类中的属性对象
     */
    open fun getDeclaredField(`object`: Any, fieldName: String?): Field? {
        var field: Field? = null
        var clazz: Class<*> = `object`.javaClass
        while (clazz != Any::class.java) {
            try {
                field = clazz.getDeclaredField(fieldName)
                return field
            } catch (e: Exception) {
                //这里甚么都不要做！并且这里的异常必须这样写，不能抛出去。
                //如果这里的异常打印或者往外抛，则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
            }
            clazz = clazz.superclass
        }
        return null
    }
}